using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.IsolatedStorage;
using System.IO;
using Microsoft.Xna.Framework;

namespace Xzipit.Utilities
{
    public class SaveFile
    {
        public int TotalPoints
        {
            get;
            set;
        }

        private int _saveNumber;
        private string _filename;

        #region Constructors
        public SaveFile()
        {
            _saveNumber = 1;
            _filename = "save" + _saveNumber + ".txt";

            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
            if (!myIsolatedStorage.FileExists(_filename))
            {
                CreateData();
            }
        }

        public SaveFile(int saveNumber)
        {
            _saveNumber = saveNumber;
            _filename = "save" + _saveNumber + ".txt";

            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
            if (!myIsolatedStorage.FileExists(_filename))
            {
                CreateData();
            }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Saves an individual level's record.
        /// </summary>
        /// <param name="levelNum"></param>
        /// <param name="worldNum"></param>
        /// <param name="newTime"></param>
        public void SaveData(int levelNum, int worldNum, double newTime, int pin)
        {
            string writeString = "";
            string[] split;
            string finalString = "";

            writeString = ReadData();
            split = writeString.Split('\n');

            // Read the save file line by line and modify the line of the level to save.
            foreach (string line in split)
            {
                if (line.Contains("p"))
                {
                    finalString += "p " + TotalPoints + "\n";
                }
                else if (!line.Equals(""))
                {
                    // by default, no changes will be made to existing level string.
                    string levelString = line.Trim();

                    // Generate the new saved line
                    if (IsLevelToSave(levelString, levelNum, worldNum)
                        && newTime < GetBestTime(levelString))
                    {
                        levelString = worldNum + "-" + levelNum + " " + newTime + " " + pin;
                    }
                    finalString += levelString + "\n";
                }
            }

            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();

            // Save the file.
            using (StreamWriter writeFile = new StreamWriter(new IsolatedStorageFileStream(_filename,
                    FileMode.Create, FileAccess.Write, myIsolatedStorage)))
            {
                writeFile.Write(finalString);
                writeFile.Flush();
                writeFile.Close();
            }

            myIsolatedStorage.Dispose();
        }

        public void WipeData()
        {
            // Since create data creates a blank file, it can be used to wipe the data as well.
            CreateData();

            GameProperties.Save.TotalPoints = 0;
        }

        public List<int> GetLevelPinColors(int worldNumber)
        {
            // get an array of the save data.
            string[] text = ReadData().Split('\n');

            // the list of pin colors
            List<int> records = new List<int>();

            foreach (string line in text)
            {
                if (string.IsNullOrEmpty(line))
                {
                    break;
                }

                // split the level record into individual attributes
                string[] split = line.Split(' ');

                if (!split[0].Equals("p"))
                {
                    // get the world number from the level string
                    int wn = Int32.Parse(split[0].Split('-')[0]);

                    // only add the pin record to to records if it is of the active world number.
                    if (wn == worldNumber)
                    {
                        records.Add(Int32.Parse(split[2]));
                    }
                }
            }

            return records;
        }

        public List<int> GetNumberOfPinsToUnlock(int worldNumber)
        {
            List<int> numPins = new List<int>();

            int min = (worldNumber - 1) * GameProperties.LEVELS_PER_WORLD;
            int max = (worldNumber) * GameProperties.LEVELS_PER_WORLD;

            for (int i = min; i < max; i++)
            {
                numPins.Add(i);
            }
            //string path = @"Content\Levels\";
            //if (worldNumber > 0)
            //{
            //    path += worldNumber + @"\";
            //}

            //path += "locked.xlvl";

            //// get an array of the save data.
            //string[] text = ReadData(path).Split('\n');

            //// the list of pin colors
            //List<int> numPins = new List<int>();

            //foreach (string line in text)
            //{
            //    if (string.IsNullOrEmpty(line))
            //    {
            //        break;
            //    }

            //    // split the level record into individual attributes
            //    string[] split = line.Split(' ');

            //    numPins.Add(Int32.Parse(split[0]));
            //}

            return numPins;
        }

        public List<int> GetWorldPinLocked()
        {
            List<int> numPins = new List<int>();

            int max = GameProperties.LEVELS_PER_WORLD * GameProperties.TOTAL_WORLDS;

            for (int i = 0; i < max; i += GameProperties.TOTAL_WORLDS)
            {
                numPins.Add(i);
            }

            return numPins;
        }

        public void LoadTotalPoints()
        {
            // get an array of the save data.
            string[] text = ReadData().Split('\n');

            // the list of pin colors
            List<int> records = new List<int>();

            foreach (string line in text)
            {
                if (string.IsNullOrEmpty(line))
                {
                    break;
                }

                // split the level record into individual attributes
                string[] split = line.Split(' ');

                if (split[0].Equals("p"))
                {
                    TotalPoints = int.Parse(split[1]);
                }
            }
        }

        #endregion

        #region Private Methods

        #region File Management
        private void CreateData()
        {
            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();

            //create new file
            using (StreamWriter writeFile = new StreamWriter(new IsolatedStorageFileStream(_filename,
                FileMode.Create, FileAccess.Write, myIsolatedStorage)))
            {
                writeFile.WriteLine("p 0");
                for (int j = 1; j <= GameProperties.TOTAL_WORLDS; j++)
                {
                    for (int i = 1; i <= GameProperties.LEVELS_PER_WORLD; i++)
                    {
                        writeFile.WriteLine(j + "-" + i + " - 4");
                    }
                }
                writeFile.Flush();
                writeFile.Close();
            }

            myIsolatedStorage.Dispose();
        }

        /// <summary>
        /// Gets the text of the save file.
        /// </summary>
        /// <returns>The raw text from the save file.</returns>
        private string ReadData()
        {
            string text;

            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
            if (!myIsolatedStorage.FileExists(_filename))
            {
                CreateData();
            }
            IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(_filename,
                                                   FileMode.Open, FileAccess.Read);
            using (StreamReader reader = new StreamReader(fileStream))
            {
                text = reader.ReadToEnd();
                reader.Close();
            }

            myIsolatedStorage.Dispose();

            return text;
        }

        private string ReadData(string filename)
        {
            string text;

            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
            
            using (StreamReader reader = new StreamReader(TitleContainer.OpenStream(filename)))
            {
                text = reader.ReadToEnd();
                reader.Close();
            }

            myIsolatedStorage.Dispose();

            return text;
        }

        #endregion

        #region Time

        private double GetBestTime(string lvlString)
        {
            string time = lvlString.Split(' ')[1].Trim();
            // Get the time from the Save File. Handles Default - Time.
            if (time.Equals("-"))
                return Double.MaxValue;
            else if (time.Equals("l"))
                return Double.MaxValue;
            else
                return double.Parse(time);
        }

        /// <summary>
        /// Tests to see if the level string is that of the level to be saved.
        /// </summary>
        /// <param name="lvlString"></param>
        /// <param name="levelNum"></param>
        /// <param name="worldNum"></param>
        /// <returns></returns>
        private bool IsLevelToSave(string lvlString, int levelNum, int worldNum)
        {
            string level = lvlString.Split(' ')[0].Trim();
            int curWorld = int.Parse(level.Split('-')[0]);
            int curLevel = int.Parse(level.Split('-')[1]);

            return (curWorld == worldNum && curLevel == levelNum);
        }

        #endregion

        #endregion
    }
}
